﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Liquid.Collections {
	/// <summary>
	/// A set of extension methods that work on an <see cref="IList&lt;T&gt;" />
	/// </summary>
	public static class Lists {
		/// <summary>
		/// Removes the first item that matches a predicate from a list
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="list">The list.</param>
		/// <param name="predicate">The predicate to test each item against, passing the item.</param>
		/// <returns>true if an item was removed</returns>
		public static bool Remove<T>(this IList<T> list, Func<T, bool> predicate) {
			for (int i = 0; i < list.Count; i++) {
				var item = list[i];
				if (predicate(item)) {
					list.RemoveAt(i);
					return true;
				}
			}
			return false;
		}

		/// <summary>
		/// Removes the first item that matches a predicate from a list
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="list">The list.</param>
		/// <param name="predicate">The predicate to test each item against, passing the item and the index in the list.</param>
		/// <returns>true if an item was removed</returns>
		public static bool Remove<T>(this IList<T> list, Func<T, int, bool> predicate) {
			for (int i = 0; i < list.Count; i++) {
				var item = list[i];
				if (predicate(item, i)) {
					list.RemoveAt(i);
					return true;
				}
			}
			return false;
		}

		/// <summary>
		/// Removes all items matching a predicate from an IList.
		/// </summary>
		/// <typeparam name="T">The type of item in the list</typeparam>
		/// <param name="list">The list.</param>
		/// <param name="predicate">The predicate to test each item against, passing the item.</param>
		/// <returns>The number of items removed</returns>
		public static int RemoveAll<T>(this IList<T> list, Func<T, bool> predicate) {
			int count = 0;
			for (int i = 0; i < list.Count; i++) {
				var item = list[i];
				if (predicate(item)) {
					list.RemoveAt(i);
					i--;
					count++;
				}
			}
			return count;
		}

		/// <summary>
		/// Removes all items matching a predicate from an IList.
		/// </summary>
		/// <typeparam name="T">The type of item in the list</typeparam>
		/// <param name="list">The list.</param>
		/// <param name="predicate">The predicate to test each item against, passing the item and the index in the list.</param>
		/// <returns>The number of items removed</returns>
		public static int RemoveAll<T>(this IList<T> list, Func<T, int, bool> predicate) {
			int count = 0;
			for (int i = 0; i < list.Count; i++) {
				var item = list[i];
				if (predicate(item, i)) {
					list.RemoveAt(i);
					i--;
					count++;
				}
			}
			return count;
		}

		public static int IndexOf<T>(this IList<T> list, Func<T, bool> predicate) {
			for (int i = 0; i < list.Count; i++) {
				var item = list[i];
				if (predicate(item))
					return i;
			}
			return -1;
		}

		public static int IndexOf<T>(this IList<T> list, Func<T, int, bool> predicate) {
			for (int i = 0; i < list.Count; i++) {
				var item = list[i];
				if (predicate(item, i))
					return i;
			}
			return -1;
		}
	}
}
